package com.power.sifa.correction.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.id.NanoId;
import cn.hutool.core.util.ObjectUtil;
import com.plf.common.domain.PageDataResponse;
import com.plf.common.domain.ResponseDTO;
import com.plf.common.domain.YesNo;
import com.plf.common.utils.CommonUtils;
import com.plf.common.utils.ExcelUtil;
import com.plf.common.utils.NanoidUtil;
import com.power.sifa.correction.api.ICrc_geopointFeign;
import com.power.sifa.correction.model.Crc_geopoint;
import com.power.sifa.correction.model.enumeration.Tp_crc_areatypeEnum;
import com.power.sifa.correction.model.pageInfo.Crc_geopointPageInfo;
import com.power.sifa.correction.service.Crc_geopointService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


/**
 * 地图范围坐标控制器
 */

@Slf4j
//@PowerLog
@RestController
@Api(value = "Crc_geopointController", tags = {"地图范围坐标"})
public class Crc_geopointController implements ICrc_geopointFeign {

    @Resource
    private Crc_geopointService crc_geopointService;


    @Override
    @ApiOperation("查询地图范围坐标分页列表")
    @SaCheckPermission("crc_geopoint_list")
    public ResponseDTO list(Crc_geopointPageInfo pageInfo) {
        Assert.notNull(pageInfo, "pageInfo参数不能为空");
        Page<Crc_geopoint> page = this.crc_geopointService.findAll(pageInfo);
        List list = new ArrayList();
        if (!page.isEmpty()) {
            for (Crc_geopoint crc_geopoint : page) {
                crc_geopoint.geneText();
                list.add(crc_geopoint);
            }
        }
        PageDataResponse p = new PageDataResponse(list, page.getTotalElements(), page.getSize(), pageInfo.getPageNumber() <= 1 ? 1 : pageInfo.getPageNumber());
        return ResponseDTO.succData(p);
    }

    @Override
    @ApiOperation("查看地图范围坐标")
    @SaCheckPermission("crc_geopoint_view")
    public ResponseDTO view(String id) {
        Assert.notNull(id, "id不能为空");
        Crc_geopoint crc_geopoint = crc_geopointService.getById(id);
        if (crc_geopoint != null) {
            crc_geopoint.geneText();
        }
        return ResponseDTO.succData(crc_geopoint);
    }

    @Override
    @ApiOperation("删除地图范围坐标")
    @SaCheckPermission("crc_geopoint_del")
    public ResponseDTO delete(String id) {
        Assert.notNull(id, "id不能为空");
        crc_geopointService.removeById(id);
        return ResponseDTO.succ();
    }

    @Override
    @ApiOperation("保存或修改地图范围坐标")
    @SaCheckPermission("crc_geopoint_save")
    public ResponseDTO save(Crc_geopoint crc_geopoint) {
        Assert.notNull(crc_geopoint, "crc_geopoint不能为空");
        if (Objects.isNull(crc_geopoint.getId())) {
            crc_geopoint.setId(NanoId.randomNanoId());
        }
        crc_geopointService.saveOrUpdate(crc_geopoint);
        return ResponseDTO.succ();
    }

    @Override
    @ApiOperation(value = "批量删除地图范围坐标")
    @SaCheckPermission("crc_geopoint_del")
    public ResponseDTO batchDel(String ids) {
        Assert.isTrue(StringUtils.hasText(ids), "ids不能为空");
        List<Integer> list = Arrays.asList(ids.split(",")).stream().map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());
        crc_geopointService.removeByIds(list);
        return ResponseDTO.succ();
    }

    @Override
    @ApiOperation(value = "导出excel")
    @SaCheckPermission("crc_geopoint_list")
    public void output(HttpServletResponse response, Crc_geopointPageInfo pageInfo) {
        Assert.notNull(pageInfo, "pageInfo不能为空");
        String title = "地图范围坐标";
        String[] heads = {"序号", "位置描述", "多边形坐标"};
        String[] fields = {"id", "name", "geopoints"};
        Page<Crc_geopoint> page = this.crc_geopointService.findAll(pageInfo);
        ExcelUtil.exportXls(title, heads, fields, page.getContent(), response);
    }

    @Override
    @ApiOperation(value = "导出excel模板")
    public void exportExcelTemplate(HttpServletResponse response) {
        String title = "地图范围坐标";
        //id自增或list从表可自行删除，需与导入项一致
        String[] heads = {"序号", "位置描述", "多边形坐标"};
        ExcelUtil.exportXls(title, heads, null, null, response);
    }

    @Override
    @ApiOperation(value = "导入excel")
    public ResponseDTO importExcel(MultipartFile file) throws IOException {
        Assert.notNull(file, "file不能为空");
        //id自增或list从表可自行删除，需与下载的模板中导入项一致
        String[] fields = {"id", "name", "geopoints"};
        List<Crc_geopoint> list = (List<Crc_geopoint>) ExcelUtil.Import(fields, file, Crc_geopoint.class);
        if (!CollectionUtils.isEmpty(list)) {
            this.crc_geopointService.saveAll(list);
        }
        return ResponseDTO.succ();
    }

    @Override
    public ResponseDTO<Boolean> existsGeopointName(String name) {
        Assert.notNull(name, "位置描述无值");

        return ResponseDTO.succData(crc_geopointService.existsGeopointName(name));
    }


    @Override
    public ResponseDTO initGeopointSecond() throws IOException {
        // 查询层级为1的数据
        Crc_geopointPageInfo pageInfo = new Crc_geopointPageInfo();
        pageInfo.setF_level(1);
        pageInfo.setPageSize(99999);
        pageInfo.setPageNumber(1);

        Page<Crc_geopoint> geopoints = crc_geopointService.findAll(pageInfo);
        if (ObjectUtil.isNotNull(geopoints)) {
            List<Crc_geopoint> geopointList = geopoints.getContent();
            // 二级节点数据
            List<Crc_geopoint> secondGeopointList = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(geopointList)) {
                // 遍历生成对应的二级节点的数据
                List<Tp_crc_areatypeEnum> enumsList = Arrays.asList(Tp_crc_areatypeEnum.values());
                geopointList.stream().forEach(el -> {
                    enumsList.stream().forEach(enumEl -> {
                        // 生成二级节点数据
                        Crc_geopoint secondGeopoint = new Crc_geopoint();
                        // 记录数据
                        secondGeopoint.setId(el.getId() + "_" + enumEl.getId());
                        secondGeopoint.setName(enumEl.getName());
                        secondGeopoint.setParentid(el.getId());
                        secondGeopoint.setLevel(2);
                        secondGeopoint.setDefaultarea(YesNo.YES);
                        secondGeopointList.add(secondGeopoint);
                    });
                });
                // 保存
                if (CollectionUtil.isNotEmpty(secondGeopointList)) {
                    secondGeopointList.stream().forEach(el -> {
                        crc_geopointService.saveOrUpdate(el);
                    });
                }
            }
        }
        return ResponseDTO.succ();
    }

    @Override
    public ResponseDTO getQueryTree() {
        List<Crc_geopoint> geopoints = crc_geopointService.findAll();
        if (ObjectUtil.isNotNull(geopoints)) {
            // 进行分类，按照字段进行区分是默认地点还是自定义地点
            List<Crc_geopoint> defaultGeopoints =
                    geopoints.stream().filter(el -> el.getDefaultarea().equals(YesNo.YES)).collect(Collectors.toList());
            List<Crc_geopoint> customerGeopoints =
                    geopoints.stream().filter(el -> el.getDefaultarea().equals(YesNo.NO)).collect(Collectors.toList());

            // 新建根节点
            AtomicInteger sort = new AtomicInteger();
            Crc_geopoint root = Crc_geopoint.builder().id(NanoId.randomNanoId()).name("自定义范围").level(0).sort(sort.get()).defaultarea(YesNo.NO).build();
            if (CollUtil.isNotEmpty(customerGeopoints)) {
                customerGeopoints.forEach(el -> {
                    el.setParentid(root.getId());
                    el.setLevel(3); // 默认节点层级为3级
                    el.setSort(sort.getAndIncrement());
                });
            }
            customerGeopoints.add(0, root);
            List<Map<String, Object>> mapList = new ArrayList<>();
            if (CollUtil.isNotEmpty(defaultGeopoints)) {
                generateDefaultTree(defaultGeopoints);
                defaultGeopoints.forEach(item -> mapList.add(BeanUtil.beanToMap(item)));
            }
            if (CollUtil.isNotEmpty(customerGeopoints)) {
                genetareCustomerTree(customerGeopoints, root);
                customerGeopoints.forEach(item -> mapList.add(BeanUtil.beanToMap(item)));
            }
            if (CollUtil.isNotEmpty(mapList)) {
                List<Map<String, Object>> result = CommonUtils.createTree(mapList, "id", "parentid", false, null);
                sortTree(result);
                return ResponseDTO.succData(result);
            }
        }
        return ResponseDTO.succ();
    }

    /**
     * 树结构按照sort排序，由小到大
     *
     * @param result
     */
    private void sortTree(List<Map<String, Object>> result) {
        if (CollectionUtil.isNotEmpty(result)) {
            result = result.stream().sorted((o1, o2) -> {
                if (Integer.parseInt(o1.get("sort").toString()) - Integer.parseInt(o2.get("sort").toString()) > 0) {
                    return 1;
                } else if (Integer.parseInt(o1.get("sort").toString()) - Integer.parseInt(o2.get("sort").toString()) < 0) {
                    return -1;
                } else {
                    return 0;
                }
            }).collect(Collectors.toList());
            result.forEach(item -> {
                List<Map<String, Object>> child = (List<Map<String, Object>>) item.get("children");
                if (CollectionUtil.isNotEmpty(child)) {
                    this.sortTree(child);
                }
            });
        }
    }

    private void genetareCustomerTree(List<Crc_geopoint> geopointList, Crc_geopoint root) {
        if (CollUtil.isNotEmpty(geopointList)) {
            Map<Integer, List<Crc_geopoint>> geopoingMap = geopointList.stream().filter(el -> ObjectUtil.isNotNull(el.getAreatype()))
                  .collect(Collectors.groupingBy(Crc_geopoint::getAreatype));
            Tp_crc_areatypeEnum[] ruleEnums = Tp_crc_areatypeEnum.values();
            AtomicInteger index = new AtomicInteger();
            for (Tp_crc_areatypeEnum areaType : ruleEnums) {
                Crc_geopoint newGeopoint = Crc_geopoint.builder().id(NanoidUtil.randomNanoId()).name(areaType.getName()).geopoints(null).parentid(root.getId())
                        .sort(index.getAndIncrement()).level(1).defaultarea(YesNo.YES).build();
                geopointList.add(newGeopoint);
                if (ObjectUtil.isNotNull(geopoingMap) && geopoingMap.containsKey(areaType.getId())) {
                    List<Crc_geopoint> childList = geopoingMap.get(areaType.getId());
                    if (CollUtil.isNotEmpty(childList)) {
                        index.set(0);
                        childList.stream().forEach(child -> {
                            child.setParentid(newGeopoint.getId());
                            child.setLevel(2);
                            child.setSort(index.getAndIncrement());
                        });
                    }
                }
            }
        }
    }


    private void generateDefaultTree(List<Crc_geopoint> geopointList) {
        if (CollUtil.isNotEmpty(geopointList)) {
            // 按照枚举进行分类排序
            // 查询层级为1的数据
            final List<Crc_geopoint> rootList = geopointList.stream().filter(el -> el.getLevel().equals(1)).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(rootList)) {
                rootList.forEach(root -> {
                    List<Crc_geopoint> childList = geopointList.stream().filter(el -> el.getParentid().equals(root.getId())).collect(Collectors.toList());
                    Tp_crc_areatypeEnum[] ruleEnums = Tp_crc_areatypeEnum.values();
                    AtomicInteger index = new AtomicInteger();
                    for (Tp_crc_areatypeEnum areaType : ruleEnums) {
                        Crc_geopoint newGeopoint = Crc_geopoint.builder().id(NanoidUtil.randomNanoId()).name(areaType.getName()).geopoints(null).parentid(root.getId())
                                .sort(index.getAndIncrement()).level(2).defaultarea(YesNo.YES).build();
                        geopointList.add(newGeopoint);
                        // 查询对应的类型的
                        if (CollUtil.isNotEmpty(childList)) {
                            index.set(0);
                            childList.stream().filter(child -> child.getAreatype().equals(areaType.getId())).forEach(child -> {
                                child.setParentid(newGeopoint.getId());
                                child.setLevel(3);
                                child.setSort(index.getAndIncrement());
                            });
                        }
                    }
                });
            }
        }
    }

    @Override
    public ResponseDTO findDefaultTreeGeopoint() {
        List<Map<String, Object>> result = new ArrayList<>();
        Crc_geopointPageInfo pageInfo = new Crc_geopointPageInfo();
        pageInfo.setF_defaultarea(YesNo.YES);
        pageInfo.setPageSize(99999);
        pageInfo.setPageNumber(1);

        Page<Crc_geopoint> geopoints = crc_geopointService.findAll(pageInfo);
        if (ObjectUtil.isNotNull(geopoints)) {
            List<Crc_geopoint> geopointList = ListUtil.toList(geopoints.getContent());
            if (CollUtil.isNotEmpty(geopointList)) {
                generateDefaultTree(geopointList);
                List<Map<String, Object>> mapList = new ArrayList<>();
                geopointList.forEach(item -> mapList.add(BeanUtil.beanToMap(item)));
                result = CommonUtils.createTree(mapList, "id", "parentid", false, null);
                sortTree(result);
            }
        }
        return ResponseDTO.succData(result);
    }


}
